using System;
using System.Reflection;
using System.Collections;
using Curriculum.DataAccess.Server;
using Curriculum.Db4oHttpModule;
using Curriculum.Modelo.Clases;
using Curriculum.Utiles;
using Db4objects.Db4o.Ext;

namespace Curriculum.Services
{
	/// <summary>
	/// Summary description for ServiceBase.
	/// </summary>
	public abstract class ServiceBase
	{
		#region Private Members

		protected ObjectServer dataManager;
//		private Transaccion _transaccion;

		#endregion

		#region Constructors

		public ServiceBase()
		{
			dataManager = new ObjectServer(Db4oHttpModule.Db4oHttpModule.Client);		
		}
		
		#endregion

		internal IExtObjectContainer Container
		{
			get { return this.dataManager.Container; }
		}

		#region Public Methods

		public IList GetAll()
		{
			return dataManager.GetAllObjects(GetMyObjectType());
		}


		public void Guardar(object obj)
		{			
			//ValidarTipos(obj);
			dataManager.SetObjejct(obj);
		}


		
		#endregion 

		#region Private & Protected Methods

		abstract protected Type GetMyObjectType();

		protected void ValidarTipos(object obj)
		{
			if (!GetMyObjectType().Equals(obj.GetType()))
			{
				throw(new Exception("El objeto no es de tipo " + GetMyObjectType().ToString()));
			}
		}

		#endregion

		/// <summary>
		/// Crea un objeto
		/// </summary>
		/// <param name="obj"></param>
		/// <returns>retorna el id con el que se dio de alta el objeto</returns>
		public object Crear(IObjetoId obj)
		{
			try
			{
				string siguienteId = IdGenerator.GetNextId(obj.GetType(), dataManager.Container);
				obj.Id = siguienteId;

				Guardar(obj);
			}
			catch (Exception ex)
			{
				throw(new Exception("Error al creal el " + obj.GetType().ToString() + ". " + ex.Message));
			}

			return obj.Id;
		}
//
//		#region Transaccion
//		public string CrearTransaccion(Transaccion transaccion)
//		{
//			_transaccion = transaccion;						
//			return transaccion.IdTransaccion;
//		}
//
//		public void DeshacerTransaccion()
//		{
//			_transaccion = null;
//		}
//
//		public void CerrarTransaccion()
//		{
//			try
//			{								
//				_transaccion.Cerrar();
//			}
//			catch (Exception ex)
//			{
//				throw(new Exception("Error al creal el " + _transaccion.TransaccionInfo + ". " + ex.Message));
//			}			
//			
//			_transaccion = null;
//		}
//
//		#endregion

		/// <summary>
		/// Modifica un objeto
		/// </summary>
		/// <param name="obj"></param>
		/// <returns>retorna el id del objeto</returns>
		public object Modificar(IObjetoId obj)
		{
			IObjetoId objDesactualizado = obj;
			try
			{
				objDesactualizado = dataManager.GetById(obj.GetType(), obj.Id) as IObjetoId;
				ActualizarObjeto(objDesactualizado, obj);

				dataManager.SetObjejct(objDesactualizado);
			}
			catch (Exception ex)
			{
				throw(new Exception("Error al modificar el " + obj.GetType().ToString() + ". " + ex.Message));
			}

			return objDesactualizado.Id;			
		}

		
		/// <summary>
		/// Elimina un objeto
		/// </summary>
		/// <param name="objId">id del objeto que se quiere eliminar</param>
		/// <returns></returns>
		public void Eliminar(Type tipo, object objId)
		{
			try
			{
				object obj = dataManager.GetById(tipo, objId.ToString());			
				dataManager.DeleteObjejct(obj);
			}
			catch (Exception ex)
			{
				throw(new Exception("Error al eliminar el " + tipo.ToString() + ". " + ex.Message));
			}
		}


		public object ObtenerObjetoPorId(Type tipo, string id)
		{
			return dataManager.GetById(tipo, id);
		}

		protected static void ActualizarObjeto(object objetoDesactualizado, object objetoActualizado)
		{
			PropertyInfo[] props = objetoDesactualizado.GetType().GetProperties();
			foreach (PropertyInfo prop in props)
			{
				MethodInfo propSetMethod = objetoActualizado.GetType().GetProperty(prop.Name).GetSetMethod();
				if (propSetMethod != null)
					propSetMethod.Invoke(objetoDesactualizado, new object[]{prop.GetValue(objetoActualizado,null)} );

				//prop.SetValue(objetoDesactualizado, prop.GetValue(objetoActualizado, null), null);
			}
		}


	}
}
